using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace InfiniTec.Security
{
    /// <summary>
    /// Extends the <see cref="ImpersonationScope"/> querying the user for a valid 
    /// username/password combination using the <see cref="QueryCredentialDialog"/>.
    /// </summary>
    public class DialogImpersonationScope : CallbackImpersonationScope
    {
        private DialogImpersonationScopeInfo _Info;
        private QueryCredentialDialog _Dialog;

        /// <summary>
        /// Gets or sets the configuration for this instance.
        /// </summary>
        public DialogImpersonationScopeInfo Info
        {
            get { return _Info; }
        }

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="targetName">The targetname and username for this instance</param>
        public DialogImpersonationScope(string targetName) : this(new DialogImpersonationScopeInfo(targetName), true) { }
        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="targetName">The targetname and username for this instance</param>
        /// <param name="impersonateImmediately">True, if an impersonation should take place immediately</param>
        public DialogImpersonationScope(string targetName, bool impersonateImmediately) : this(new DialogImpersonationScopeInfo(targetName), impersonateImmediately) { }

        /// <summary>
        /// Initializes a new instance of this class using the specified startup info.
        /// </summary>
        /// <param name="info">The <see cref="DialogImpersonationScopeInfo"/> for this instance.</param>
        public DialogImpersonationScope(DialogImpersonationScopeInfo info) : this(info, true) { }

        /// <summary>
        /// Creates a new instance of this class and impersonates as the user specified by targetName.
        /// </summary>
        /// <param name="info">The targetName of the identity, as stored in the <see cref="CredentialManager"/>,</param>
        /// <param name="impersonateImmediately">True, if an impersonation should take place immediately</param>
        public DialogImpersonationScope(DialogImpersonationScopeInfo info, bool impersonateImmediately)
            : base(info.TargetName, null, info.LogonType, false)
        {
            _Info = info;

            CredentialCallback = AcquireCredential;

            if (impersonateImmediately) Impersonate();
        }

        /// <summary>
        /// Invalidates the credential in the <see cref="CredentialManager"/> as well as
        /// in the Windows Credential manager.
        /// </summary>
        public override void Invalidate()
        {
            base.Invalidate();
            if (_Dialog != null) _Dialog.ConfirmCredentials(false);
        }
        /// <summary>
        /// Confirms the credential in the <see cref="CredentialManager"/> as well as
        /// in the Windows Credential manager.
        /// </summary>
        public override void Confirm()
        {
            base.Confirm();
            if (_Dialog != null) _Dialog.ConfirmCredentials(true);
            
        }
        private void AcquireCredential(object source, AcquireCredentialEventArgs e)
        {
            _Dialog = new QueryCredentialDialog();
            _Dialog.CaptionText = Info.Caption;
            _Dialog.MessageText = Info.MessageText;
            _Dialog.Image = Info.Image;
            _Dialog.Username = Info.DefaultUsername;
            _Dialog.Options = Info.Options;

            if (e.AttemptCount != 0)
            {
                _Dialog.Options |= QueryCredentialOptions.IncorrectPassword;
            }
            else
            {
                _Dialog.Options &= ~QueryCredentialOptions.IncorrectPassword;
            }

            _Dialog.TargetName = e.TargetName;
            _Dialog.TargetName = e.TargetName;
            if (_Dialog.ShowDialog() != DialogResult.OK)
            {
                e.Cancel = true;
                return;
            }
            Info.DefaultUsername = _Dialog.Username;
            e.Username = _Dialog.Username;
            e.Password = _Dialog.Password;
            e.Cancel = false;
        }

    }
}